package com.kaipizhe.config;

import com.kaipizhe.service.PermissionService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotNull;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.function.Supplier;

// 注入RequestMappingHandlerMapping
@Component
public class CustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    private final PermissionService permissionService;
    private final RequestMappingHandlerMapping requestMappingHandlerMapping;
    private final CustomUrlPatternExtractor customUrlPatternExtractor;

    public CustomAuthorizationManager(PermissionService permissionService,
                                      RequestMappingHandlerMapping requestMappingHandlerMapping, CustomUrlPatternExtractor customUrlPatternExtractor) {
        this.permissionService = permissionService;
        this.requestMappingHandlerMapping = requestMappingHandlerMapping;
        this.customUrlPatternExtractor = customUrlPatternExtractor;
    }

    private String getFirstPattern(String[] values, String[] paths) {
        if (values.length > 0 && !values[0].isEmpty()) {
            return values[0];
        }
        if (paths.length > 0 && !paths[0].isEmpty()) {
            return paths[0];
        }
        return "";
    }

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
        if (authentication.get() != null) {
            // 创始人直接放行
            long count = authentication.get().getAuthorities().stream()
                    .filter(o -> o.getAuthority().equals("SCOPE_ROLE_1"))
                    .count();
            if (count > 0) {
                return new AuthorizationDecision(true);
            }

            customUrlPatternExtractor.extractAllUrls();

            // 获取动态URL模式
            String dynamicUrlPattern = getDynamicUrlPattern(object.getRequest());
            System.out.println(dynamicUrlPattern);
            String username = authentication.get().getName();

            if (StringUtils.hasText(dynamicUrlPattern) && StringUtils.hasText(username)) {
                // 用动态URL模式去查询权限
                if (permissionService.hasPermissionByPattern(username, dynamicUrlPattern)) {
                    return new AuthorizationDecision(true);
                }
            }
        }

        throw new AccessDeniedException("没有权限访问！");
    }

    /**
     * 获取请求对应的动态URL模式
     */
    private String getDynamicUrlPattern(HttpServletRequest request) {
        try {
            // 方法1: 通过RequestMappingHandlerMapping获取HandlerExecutionChain
            HandlerExecutionChain executionChain = requestMappingHandlerMapping.getHandler(request);

            if (executionChain != null && executionChain.getHandler() instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) executionChain.getHandler();
                return extractMappingPattern(handlerMethod);
            }
        } catch (Exception e) {
            // 如果出错，降级使用原始URL
            System.err.println("Failed to get dynamic URL pattern: " + e.getMessage());
        }

        // 降级方案：返回原始请求URI
        return request.getRequestURI();
    }

    /**
     * 从HandlerMethod中提取映射模式（包含类级别前缀）
     */
    private String extractMappingPattern(HandlerMethod handlerMethod) {
        // 关键：先获取类级别的RequestMapping前缀
        String classPattern = getClassLevelPattern(handlerMethod);
        String methodPattern = getMethodLevelPattern(handlerMethod);

        // 组合类级别和方法级别的路径
        return combinePatterns(classPattern, methodPattern);
    }

    /**
     * 获取类级别的RequestMapping路径
     */
    private String getClassLevelPattern(HandlerMethod handlerMethod) {
        Class<?> controllerClass = handlerMethod.getBeanType();

        // 检查@RequestMapping注解
        RequestMapping classRequestMapping = controllerClass.getAnnotation(RequestMapping.class);
        if (classRequestMapping != null) {
            return getFirstPattern(classRequestMapping.value(), classRequestMapping.path());
        }

        // 检查@RestController上的路径（如果有的话）
        // 有些项目可能在@RestController注解上也定义路径
        return "";
    }

    /**
     * 获取方法级别的映射路径
     */
    private String getMethodLevelPattern(HandlerMethod handlerMethod) {
        // 检查DeleteMapping
        DeleteMapping deleteMapping = handlerMethod.getMethodAnnotation(DeleteMapping.class);
        if (deleteMapping != null) {
            return getFirstPattern(deleteMapping.value(), deleteMapping.path());
        }

        // 检查PostMapping
        PostMapping postMapping = handlerMethod.getMethodAnnotation(PostMapping.class);
        if (postMapping != null) {
            return getFirstPattern(postMapping.value(), postMapping.path());
        }

        // 检查GetMapping
        GetMapping getMapping = handlerMethod.getMethodAnnotation(GetMapping.class);
        if (getMapping != null) {
            return getFirstPattern(getMapping.value(), getMapping.path());
        }

        // 检查PutMapping
        PutMapping putMapping = handlerMethod.getMethodAnnotation(PutMapping.class);
        if (putMapping != null) {
            return getFirstPattern(putMapping.value(), putMapping.path());
        }

        // 检查RequestMapping
        RequestMapping requestMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
        if (requestMapping != null) {
            return getFirstPattern(requestMapping.value(), requestMapping.path());
        }

        return "";
    }

    /**
     * 组合类级别和方法级别的路径模式
     */
    private String combinePatterns(String classPattern, String methodPattern) {
        // 如果类级别没有路径，直接返回方法级别路径
        if (!StringUtils.hasText(classPattern)) {
            return StringUtils.hasText(methodPattern) ? methodPattern : "";
        }

        // 如果方法级别没有路径，返回类级别路径
        if (!StringUtils.hasText(methodPattern)) {
            return classPattern;
        }

        // 组合两个路径
        String combined = classPattern;

        // 保证类路径以/结尾
        if (!classPattern.endsWith("/")) {
            combined += "/";
        }

        // 处理方法路径的开头/
        if (methodPattern.startsWith("/")) {
            combined += methodPattern.substring(1);
        } else {
            combined += methodPattern;
        }

        // 保证最终路径以/开头
        if (!combined.startsWith("/")) {
            combined = "/" + combined;
        }

        return combined;
    }
}


